﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Reactor.Client.Controls
{
    public class BorderedImageButton : ButtonBase
    {
        private readonly Grid _rootGrid;
        private TextBlock _buttonLabel;
        private readonly Image _image;
        private Storyboard _mouseoverStoryboard;
        private Storyboard _mouseoutStoryboard;
        private readonly Rectangle _outterRectangle;
        private const int UpscaleAmount = 5;
        private Color _labelColor = Colors.Black;
        private readonly Duration _animationDuration = TimeSpan.FromMilliseconds(150);

        public BorderedImageButton()
        {
            _rootGrid = new Grid();
            _image = new Image
            {
                Margin = new Thickness(10),
                MinHeight = 24,
                MinWidth = 24
            };
            _outterRectangle = new Rectangle
            {
                Margin = new Thickness(5),
                RadiusX = 5,
                RadiusY = 5,
                StrokeThickness = 1,
                Effect = new DropShadowEffect { Color = Colors.DarkGray },
                Fill = new SolidColorBrush(Colors.White),
                Stroke = new SolidColorBrush(Colors.Gray)
            };
            _rootGrid.Children.Add(_outterRectangle);
            _rootGrid.Children.Add(_image);

            Background = new SolidColorBrush(Colors.Transparent);
            BorderThickness = new Thickness(0);
            Height = double.IsNaN(Height) ? 50 : Height;
            Width = double.IsNaN(Width) ? 50 : Width;
            Content = _rootGrid;

            CreateStoryboards();

            ClickMode = ClickMode.Hover;

            MouseEnter += (s, e) => _mouseoverStoryboard.Begin();
            MouseLeave += (s, e) => _mouseoutStoryboard.Begin();

            MouseLeftButtonDown += (s, e) =>
            {
                _mouseoverStoryboard.Stop();
                _mouseoutStoryboard.Begin();
            };
            MouseLeftButtonUp += (s, e) =>
            {
                _mouseoutStoryboard.Stop();
                _mouseoverStoryboard.Begin();

                if (ActualCommand != null)
                    ActualCommand.Execute(CommandParameter);
            };
        }

        private void CreateStoryboards()
        {
            CreateMouseOverStoryboard();
            CreateMouseOutStoryboard();
        }

        private void CreateMouseOutStoryboard()
        {
            _mouseoutStoryboard = new Storyboard();

            var mouseoutWidthAnimation = new DoubleAnimation();
            Storyboard.SetTarget(mouseoutWidthAnimation, this);
            Storyboard.SetTargetProperty(mouseoutWidthAnimation, new PropertyPath(WidthProperty));
            mouseoutWidthAnimation.From = Width + UpscaleAmount;
            mouseoutWidthAnimation.To = Width;
            mouseoutWidthAnimation.Duration = _animationDuration;
            _mouseoutStoryboard.Children.Add(mouseoutWidthAnimation);

            var mouseoutHeightAnimation = new DoubleAnimation();
            Storyboard.SetTarget(mouseoutHeightAnimation, this);
            Storyboard.SetTargetProperty(mouseoutHeightAnimation, new PropertyPath(HeightProperty));
            mouseoutHeightAnimation.From = Height + UpscaleAmount;
            mouseoutHeightAnimation.To = Height;
            mouseoutHeightAnimation.Duration = _animationDuration;
            _mouseoutStoryboard.Children.Add(mouseoutHeightAnimation);
        }

        private void CreateMouseOverStoryboard()
        {
            _mouseoverStoryboard = new Storyboard();
            var mouseoverWidthAnimation = new DoubleAnimation();
            Storyboard.SetTarget(mouseoverWidthAnimation, this);
            Storyboard.SetTargetProperty(mouseoverWidthAnimation, new PropertyPath(WidthProperty));
            mouseoverWidthAnimation.From = Width;
            mouseoverWidthAnimation.To = Width + UpscaleAmount;
            mouseoverWidthAnimation.Duration = _animationDuration;
            _mouseoverStoryboard.Children.Add(mouseoverWidthAnimation);

            var mouseoverHeightAnimation = new DoubleAnimation();
            Storyboard.SetTarget(mouseoverHeightAnimation, this);
            Storyboard.SetTargetProperty(mouseoverHeightAnimation, new PropertyPath(HeightProperty));
            mouseoverHeightAnimation.From = Height;
            mouseoverHeightAnimation.To = Height + UpscaleAmount;
            mouseoverHeightAnimation.Duration = _animationDuration;
            _mouseoverStoryboard.Children.Add(mouseoverHeightAnimation);
        }

        #region ImageSource Dependency Property

        private static readonly PropertyMetadata PropMetadata = new PropertyMetadata((s, e) =>
        {
            var ctrl = s as BorderedImageButton;
            if (ctrl == null) throw new InvalidOperationException("Control must be of type BorderedImageButton.");

            if (e.NewValue is string)
                ctrl._image.Source = new BitmapImage(new Uri(Application.Current.Host.Source, e.NewValue.ToString()));
        });

        /// <summary>
        /// Identifies the ImageSource dependency property.
        /// </summary>
        public static DependencyProperty ImageSourceProperty =
            DependencyProperty.Register("ImageSource", typeof(string), typeof(BorderedImageButton), PropMetadata);

        /// <summary>
        /// Image source for the image used as the template for this button.
        /// </summary>
        public string ImageSource
        {
            get { return (string)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }
        }

        #endregion

        #region Command Dependency Property

        private static readonly PropertyMetadata CommandPropMetadata = new PropertyMetadata((s, e) =>
        {
            var ctrl = s as BorderedImageButton;
            if (ctrl == null) throw new InvalidOperationException("Control must be of type BorderedImageButton.");
        });

        public static DependencyProperty ActualCommandProperty =
            DependencyProperty.Register("ActualCommand", typeof(ICommand), typeof(BorderedImageButton), CommandPropMetadata);

        public ICommand ActualCommand
        {
            get { return (ICommand)GetValue(ActualCommandProperty); }
            set { SetValue(ActualCommandProperty, value); }
        }

        #endregion

        #region Label Dependency Property

        private static void UpdateLabelControl(DependencyObject s, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = s as BorderedImageButton;
            if (ctrl == null) throw new InvalidOperationException("Control must be of type BorderedImageButton.");

            var value = (e.NewValue == null) ? string.Empty : e.NewValue.ToString();

            if (ctrl._buttonLabel == null)
                ctrl.CreateButtonLabel(value);
            else
                ctrl._buttonLabel.Text = value;
        }

        public static DependencyProperty LabelProperty =
            DependencyProperty.Register("Label", typeof(string), typeof(BorderedImageButton), new PropertyMetadata("0", UpdateLabelControl));

        public string Label
        {
            get { return (string)GetValue(LabelProperty); }
            set { SetValue(LabelProperty, value); }
        }

        private void CreateButtonLabel(string value)
        {
            _buttonLabel = new TextBlock
                               {
                                   Text = value,
                                   Foreground = new SolidColorBrush(Colors.Red),
                                   FontWeight = FontWeights.Bold,
                                   FontSize = 14,
                                   HorizontalAlignment = HorizontalAlignment.Center,
                                   VerticalAlignment = VerticalAlignment.Center
                               };
            _rootGrid.Children.Add(_buttonLabel);
        }

        #endregion

        #region Label Dependency Property

        private static void UpdateLabelColor(DependencyObject s, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = s as BorderedImageButton;
            if (ctrl == null) throw new InvalidOperationException("Control must be of type BorderedImageButton.");

            ctrl._labelColor = (Color) e.NewValue;

            if (ctrl._buttonLabel != null)
                ctrl._buttonLabel.Foreground = new SolidColorBrush(ctrl._labelColor);
        }

        public static DependencyProperty LabelColorProperty =
            DependencyProperty.Register("LabelColor", typeof(Color), typeof(BorderedImageButton), new PropertyMetadata(Colors.Black, UpdateLabelColor));

        public Color LabelColor
        {
            get { return (Color)GetValue(LabelColorProperty); }
            set { SetValue(LabelColorProperty, value); }
        }

        #endregion
    }
}
